#pragma once

#ifndef SETTINGS__TABLE__INCLUDED__HH__
#define SETTINGS__TABLE__INCLUDED__HH__

#include <qheaderview.h>
#include <qtablewidget.h>
#include <qlabel.h>
#include <qboxlayout.h>
#include <qscrollbar.h>
#include <LitString.h>
#include <LitExceptions.h>
#include "SettingsItem.h"

class SettingsList
{
public:
	typedef std::vector<SettingsItem*> ItemList;

public:
	ItemList mList;

public:
	SettingsList( );
	SettingsList( const SettingsList& rk );
	virtual ~SettingsList( );
	ItemList::iterator begin(){ return mList.begin(); }
	ItemList::const_iterator begin() const{ return mList.begin(); }
	ItemList::iterator end(){ return mList.end(); }
	ItemList::const_iterator end() const{ return mList.end(); }
	void reloadSettings();
	void saveSettings();

	bool hasItem( const std::string &name ) const;
	ItemList::iterator findItem( const std::string &name );
	ItemList::const_iterator findItem( const std::string &name ) const;
	SettingsItem* addItem( SettingsItem*itm );
	void clear();
	bool removeItem( const std::string &name );
	bool removeItem( ItemList::iterator itor );
	size_t size() const;
	bool empty() const;
};

class SettingsTable : public QTableWidget
{
	Q_OBJECT
protected:
	SettingsList mList;

public:
	SettingsTable( QWidget * parent );
	virtual ~SettingsTable();

	void _makeEnoughRows();
	size_t _currentRow();
	void connect( SettingsItem * itm );
	template<typename T>
	T * _addRow( T * itm )
	{
		if( !mList.addItem( itm ) ) return itm;
		_makeEnoughRows( );
		size_t id = _currentRow();
		QLabel * lbl = new QLabel( itm->getName().c_str(), this );
		setCellWidget( id, 0, lbl );
		setCellWidget( id, 1, itm );
		connect( itm );
		setRowHeight( id, itm->sizeHint().height() );
		return itm;
	}

	void reloadSettings();
	void saveSettings();

	SettingsTextItem* addSetting( const std::string &name, const char* value, bool modifiable = true );
	SettingsTextItem* addSetting( const std::string &name, const std::string &value, bool modifiable = true );
	SettingsTextItem* addSetting( const std::string &name, const QString &value, bool modifiable = true );
	
	SettingsTableItem* addSetting( const std::string &name, bool modifiable=true );
	SettingsComboItem* addSetting( const std::string &name, const Lit::StringList &value, bool modifiable = true );
	SettingsCheckboxItem* addSetting( const std::string &name, bool value, bool modifiable = true );
	SettingsVectorItem* addSetting( const std::string &name, const Ogre::Vector3& value, bool inline_=true, bool modifiable = true );
	SettingsDegreeItem* addSetting( const std::string &name, const Ogre::Degree& value, bool modifiable = true );
	SettingsColorItem* addSetting( const std::string &name, const Ogre::ColourValue& value, bool modifiable = true );
	SettingsColorItem* addSetting( const std::string &name, const QColor& value, bool modifiable = true );
	SettingsTextItem* addSetting( const std::string &name, const Ogre::Real& value, bool modifiable = true );
	SettingsDegreeItem* addSetting( const std::string &name, const Ogre::Radian& value, bool modifiable = true );
	SettingsQuaternionItem* addSetting( const std::string &name, const Ogre::Quaternion& value, bool modifiable = true );
	SettingsTableItem* addSettingsTable( const std::string &name, bool modifiable = true );
	template<typename T>T * addSetting( const std::string &name, T* w, bool modifiable = true, const char * changed_member_func = NULL, QObject* rcvr = NULL, const char * apply_change_func = NULL ){
		_addRow( new SettingsItemWidget<T>( name, w, modifiable, changed_member_func, rcvr, apply_change_func ) );
		return w;
	}

	void removeSetting( const std::string &name );
	bool hasSetting( const std::string &name ) const;
	template<typename T>
	T * getSetting( const std::string &name )
	{
		T * ret = (T*)(findSetting(name));
		if( ret ) return ret;
		throw Lit::ItemMissing(name, "SettingTable",EXC_LOC);
		return NULL;
	}
	SettingsItem * findSetting( const std::string &name );
	void clear();
	size_t size() const;
	bool empty() const;

signals:
	void settingChanged( const std::string &_nam, const std::string &_val );
};

class SettingsWidget : public QWidget
{
	Q_OBJECT
public:
	struct Page
	{
		Page( );
		Page( const Page &rk );
		~Page();
		Page& operator = ( const Page &rk );

		void create( const std::string &name_, QTabWidget * widget );
		void destroy();
		QTabWidget* tabWidget;
		int id;
		std::string name;
		SettingsTable * table;
	};
	typedef std::list<Page*> list_t;
	list_t mTabList;

	void adjustSize( )
	{
		for( auto i=mTabList.begin(); i!=mTabList.end(); i++ )
			if( (*i)->table->sizeHint().width() > mTabs->minimumWidth() )
				mTabs->setMinimumWidth((*i)->table->sizeHint().width()+(*i)->table->verticalScrollBar()->sizeHint().width()*2);
	}
	QTabWidget * mTabs;
	QVBoxLayout* mLay;
signals:
	void settingChanged( const std::string &page_name, const std::string &name, const std::string &value );
	void currentPageChanged(int);
protected slots:
	void _settingChanged( const std::string &_name, const std::string &val );
public:
	SettingsWidget( QWidget * parent );
	~SettingsWidget( );

	void reloadPages();
	void savePages();

	void savePage( const std::string &name );
	void reloadPage( const std::string &name );

	Page* createPage( const std::string &name );
	void removePage( const std::string &name, bool erase = true );
	
	int findPageId( const std::string &name );
	std::string findPageName( int id );

	bool hasPage( const std::string &name ) const;
	list_t::iterator findPage( const std::string &name );
	list_t::const_iterator findPage( const std::string &name ) const;
	void clearPages();
};

#endif